// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "BufferReader.h"
#include <cstring>
#include <MemoryManagement/VmiBuffer.h>
#include "HWSecure/include/securec.h"

/**
* @brief : BufferReader construtor,init the member variables:m_data m_len m_writePos
* @param [in]data: first object :the data
                   second object:the length of data
*/
BufferReader::BufferReader(std::pair<uint8_t*, size_t> data)
    : m_data(data.first), m_len(data.second), m_readPos(0)
{
}

/**
 * @brief: consturct BufferReader from VmiBuffer
 * @param buf : vimBuffer
 */
BufferReader::BufferReader(const VmiBuffer& buf)
    : m_data(buf.GetPointer()), m_len(buf.GetSize()), m_readPos(0)
{
}

/**
* @brief : BufferReader destructor
*/
BufferReader::~BufferReader()
{
    m_data = nullptr;
    m_len = 0;
    m_readPos = 0;
}

/**
* @brief : overload operator []
* @param [in]value: the position of data
* @return : the value of specified data
*/
uint8_t BufferReader::operator[](size_t pos) const
{
    return Read<uint8_t>(pos);
}

/**
* @brief : get the position of data
* @return : the position of data
*/
size_t BufferReader::GetReadPosition() const
{
    return m_readPos;
}

/**
* @brief : set the read position and return it
* @param [in]pos: the read position
* @return : the Write position
*/
size_t BufferReader::SetReadPosition(size_t pos)
{
    if (pos > m_len) {
        ERR("SetReadPosition error, pos = %zu, m_len = %zu", pos, m_len);
        m_errno = ERROR;
        return m_readPos;
    }
    m_readPos = pos;
    return m_readPos;
}

/**
* @brief : skip data of specified length
* @param [in]skip: the specified length
*/
void BufferReader::Skip(size_t skip)
{
    if (skip > Remain()) {
        ERR("skip > Remain() skip = %zu, Remain = %zu", skip, Remain());
        m_errno = ERROR;
        return;
    }

    m_readPos += skip;
}

/**
* @brief : read the data of type uint8_t
* @param [in]dest: first object:the destination to save data
                   second object: the length of data
*/
void BufferReader::Read(std::pair<uint8_t*, size_t> dest)
{
    uint8_t* data = dest.first;
    size_t dataLen = dest.second;
    if (dataLen > Remain()) {
        ERR("dataLen > Remain(), dataLen = %zu, Remain = %zu,", dataLen, Remain());
        m_errno = ERROR;
        return;
    }

    if (data == nullptr) {
        ERR("data is nullptr");
        m_errno = ERROR;
        return;
    }

    if (IsDataNull()) {
        ERR("m_data is null");
        m_errno = ERROR;
        return;
    }

    errno_t ret = memcpy_s(data, dataLen, &m_data[m_readPos], dataLen);
    if (ret != EOK) {
        ERR("memcpy_s data failed, ret = %d!", ret);
        m_errno = ERROR;
        return;
    }

    m_readPos += dataLen;
}

/**
* @brief : get the first address of m_data
* @return : the first address of m_data
*/
uint8_t* BufferReader::Data() const
{
    return &m_data[0];
}

/**
* @brief : judge if the data address is null
* @return : true: the data address is null,
            false:the data address is no null,
*/
bool BufferReader::IsDataNull() const
{
    return m_data == nullptr;
}

/**
* @brief : get the length of data which is waiting to read
* @return : the length
*/
size_t BufferReader::Length() const
{
    return m_len;
}

/**
* @brief : get the length of remaining data
* @return : the length
*/
size_t BufferReader::Remain() const
{
    return (m_readPos >= m_len) ? 0 : (m_len - m_readPos);
}

/**
* @brief : finish the read buffer
*/
void BufferReader::Done()
{
    Skip(Remain());
}

/**
 * @brief : get error number
 * @return : error number
 */
int BufferReader::GetErrorNumber() const
{
    return m_errno;
}

/**
 * @brief : reset error number
 */
void BufferReader::ResetErrorNumber()
{
    m_errno = OK;
}


